package com.example.project.utils;

import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.time.Duration;
import java.util.Locale;
import java.util.ResourceBundle;
import org.apache.commons.lang3.time.DateFormatUtils;

/**
 * 时间工具类
 * 
 * @author ruoyi
 */
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {

	public static String YYYY = "yyyy";

	public static String YYYY_MM = "yyyy-MM";

	public static String YYYY_MM_DD = "yyyy-MM-dd";

	public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";

	public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

	private static String[] parsePatterns = { "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
			"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss",
			"yyyy.MM.dd HH:mm", "yyyy.MM" };

	/**
	 * 获取当前Date型日期
	 * 
	 * @return Date() 当前日期
	 */
	public static Date getNowDate() {
		return new Date();
	}

	public static LocalDateTime curLocalDateTime() {
		return LocalDateTime.now();
	}

	/**
	 * 字符串转LocalDateTime
	 * 
	 * @param dateStr 日期字符串
	 * @param pattern 日期格式，默认为"yyyy-MM-dd HH:mm:ss"
	 * @return LocalDateTime对象
	 */
	public static LocalDateTime parseLocalDateTime(String dateStr, String pattern) {
		if (dateStr == null || dateStr.trim().isEmpty()) {
			return null;
		}
		if (pattern == null || pattern.trim().isEmpty()) {
			pattern = YYYY_MM_DD_HH_MM_SS;
		}
		try {
			SimpleDateFormat sdf = new SimpleDateFormat(pattern);
			Date date = sdf.parse(dateStr);
			return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
		} catch (ParseException e) {
			throw new IllegalArgumentException("日期格式错误: " + dateStr + "，期望格式: " + pattern, e);
		}
	}

	/**
	 * 字符串转LocalDateTime（使用默认格式"yyyy-MM-dd HH:mm:ss"）
	 * 
	 * @param dateStr 日期字符串
	 * @return LocalDateTime对象
	 */
	public static LocalDateTime parseLocalDateTime(String dateStr) {
		return parseLocalDateTime(dateStr, YYYY_MM_DD_HH_MM_SS);
	}

	/**
	 * 字符串转LocalDate
	 * 
	 * @param dateStr 日期字符串
	 * @param pattern 日期格式，默认为"yyyy-MM-dd"
	 * @return LocalDate对象
	 */
	public static LocalDate parseLocalDate(String dateStr, String pattern) {
		if (dateStr == null || dateStr.trim().isEmpty()) {
			return null;
		}
		if (pattern == null || pattern.trim().isEmpty()) {
			pattern = YYYY_MM_DD;
		}
		try {
			SimpleDateFormat sdf = new SimpleDateFormat(pattern);
			Date date = sdf.parse(dateStr);
			return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
		} catch (ParseException e) {
			throw new IllegalArgumentException("日期格式错误: " + dateStr + "，期望格式: " + pattern, e);
		}
	}

	/**
	 * 字符串转LocalDate（使用默认格式"yyyy-MM-dd"）
	 * 
	 * @param dateStr 日期字符串
	 * @return LocalDate对象
	 */
	public static LocalDate parseLocalDate(String dateStr) {
		return parseLocalDate(dateStr, YYYY_MM_DD);
	}

	/**
	 * 获取当前日期, 默认格式为yyyy-MM-dd
	 * 
	 * @return String
	 */
	public static String getDate() {
		return dateTimeNow(YYYY_MM_DD);
	}

	public static final String getTime() {
		return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
	}

	public static final String dateTimeNow() {
		return dateTimeNow(YYYYMMDDHHMMSS);
	}

	public static final String dateTimeNow(final String format) {
		return parseDateToStr(format, new Date());
	}

	public static final String dateTime(final Date date) {
		return parseDateToStr(YYYY_MM_DD, date);
	}

	public static final String parseDateToStr(final String format, final Date date) {
		return new SimpleDateFormat(format).format(date);
	}

	public static final Date dateTime(final String format, final String ts) {
		try {
			return new SimpleDateFormat(format).parse(ts);
		} catch (ParseException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 日期路径 即年/月/日 如2018/08/08
	 */
	public static final String datePath() {
		Date now = new Date();
		return DateFormatUtils.format(now, "yyyy/MM/dd");
	}

	/**
	 * 日期路径 即年/月/日 如20180808
	 */
	public static final String dateTime() {
		Date now = new Date();
		return DateFormatUtils.format(now, "yyyyMMdd");
	}

	/**
	 * 日期型字符串转化为日期 格式
	 */
	public static Date parseDate(Object str) {
		if (str == null) {
			return null;
		}
		try {
			return parseDate(str.toString(), parsePatterns);
		} catch (ParseException e) {
			return null;
		}
	}

	/**
	 * 获取服务器启动时间
	 */
	public static Date getServerStartDate() {
		long time = ManagementFactory.getRuntimeMXBean().getStartTime();
		return new Date(time);
	}

	/**
	 * 计算相差天数
	 */
	public static int differentDaysByMillisecond(Date date1, Date date2) {
		return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
	}

	/**
	 * 计算时间差
	 *
	 * @param endDate   最后时间
	 * @param startTime 开始时间
	 * @return 时间差（天/小时/分钟）
	 */
	public static String timeDistance(Date endDate, Date startTime) {
		long nd = 1000 * 24 * 60 * 60;
		long nh = 1000 * 60 * 60;
		long nm = 1000 * 60;
		// long ns = 1000;
		// 获得两个时间的毫秒时间差异
		long diff = endDate.getTime() - startTime.getTime();
		// 计算差多少天
		long day = diff / nd;
		// 计算差多少小时
		long hour = diff % nd / nh;
		// 计算差多少分钟
		long min = diff % nd % nh / nm;
		// 计算差多少秒//输出结果
		// long sec = diff % nd % nh % nm / ns;
		return day + "天" + hour + "小时" + min + "分钟";
	}

	/**
	 * 增加 LocalDateTime ==> Date
	 */
	public static Date toDate(LocalDateTime temporalAccessor) {
		ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());
		return Date.from(zdt.toInstant());
	}

	/**
	 * 将LocalDate格式化为指定格式的字符串
	 * 
	 * @param date    LocalDate对象
	 * @param pattern 日期格式，默认为"yyyy-MM-dd"
	 * @return 格式化后的字符串
	 */
	public static String formatLocalDate(LocalDate date, String pattern) {
		if (date == null) {
			return null;
		}
		if (pattern == null || pattern.trim().isEmpty()) {
			pattern = YYYY_MM_DD;
		}
		return date.format(DateTimeFormatter.ofPattern(pattern));
	}

	/**
	 * 将LocalDateTime格式化为指定格式的字符串
	 * 
	 * @param temporalAccessor LocalDateTime对象
	 * @param format           日期格式，默认为"yyyy-MM-dd HH:mm:ss"
	 * @return 格式化后的字符串
	 */
	public static final String formatLocalDateTime(LocalDateTime temporalAccessor, String format) {
		if (temporalAccessor == null) {
			return null;
		}
		if (format == null || format.trim().isEmpty()) {
			format = YYYY_MM_DD_HH_MM_SS;
		}
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
		return temporalAccessor.format(formatter);
	}

	/**
	 * 将LocalDateTime格式化为默认格式的字符串（"yyyy-MM-dd HH:mm:ss"）
	 * 
	 * @param temporalAccessor LocalDateTime对象
	 * @return 格式化后的字符串
	 */
	public static final String formatLocalDateTime(LocalDateTime temporalAccessor) {
		return formatLocalDateTime(temporalAccessor, YYYY_MM_DD_HH_MM_SS);
	}

	/**
	 * 增加 LocalDate ==> Date
	 */
	public static Date toDate(LocalDate temporalAccessor) {
		LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));
		ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
		return Date.from(zdt.toInstant());
	}

	/**
	 * 计算距离指定时间的时长
	 * 
	 * @param createTime 目标时间
	 * @return 格式化后的时间字符串（如"5天"、"3小时"、"45分钟"）
	 */
	public static String calculateTimeSince(LocalDateTime createTime) {
		LocalDateTime now = LocalDateTime.now();
		long minutesDiff = java.time.Duration.between(createTime, now).toMinutes();
		long hoursDiff = minutesDiff / 60;

		if (hoursDiff >= 24) {
			// 超过24小时按天计算，不足一天的部分也按一天计算
			long daysDiff = (hoursDiff + 23) / 24; // 向上取整
			return "大约" + daysDiff + "天";
		} else if (hoursDiff >= 1) {
			return "大约" + hoursDiff + "小时";
		} else {
			return minutesDiff + "分钟";
		}
	}

	/**
	 * 格式化预计时间字段
	 * 
	 * @param estimatedHours 原始预计时间字符串
	 * @return 格式化后的预计时间字符串
	 */
	public static String formatEstimatedHours(String estimatedHours) {
		if (estimatedHours == null || estimatedHours.trim().isEmpty()) {
			return estimatedHours;
		}

		String value = estimatedHours.trim();

		// 检查是否包含冒号
		if (value.contains(":")) {
			String[] parts = value.split(":");
			if (parts.length == 2) {
				try {
					int hours = Integer.parseInt(parts[0]);
					int minutes = Integer.parseInt(parts[1]);

					// 如果分钟数超过60，进行进位处理
					if (minutes >= 60) {
						hours += minutes / 60;
						minutes = minutes % 60;
					}

					// 格式化分钟数为两位数
					return hours + ":" + String.format("%02d", minutes);
				} catch (NumberFormatException e) {
					// 如果解析失败，返回原始值
					return value;
				}
			}
		} else {
			// 如果没有冒号，补充 ":00"
			try {
				Integer.parseInt(value); // 验证是否为纯数字
				return value + ":00";
			} catch (NumberFormatException e) {
				// 如果不是纯数字，返回原始值
				return value;
			}
		}

		return value;
	}

	/**
	 * 获取指定天数前的日期
	 * 
	 * @param days 天数（正数表示过去，负数表示未来）
	 * @return 指定天数前的日期字符串（格式：yyyy-MM-dd）
	 */
	public static String getDateBefore(int days) {
		java.util.Calendar calendar = java.util.Calendar.getInstance();
		calendar.add(java.util.Calendar.DAY_OF_MONTH, -days);
		return parseDateToStr(YYYY_MM_DD, calendar.getTime());
	}

	/**
	 * 获取指定天数前的日期对象
	 * 
	 * @param days 天数（正数表示过去，负数表示未来）
	 * @return 指定天数前的Date对象
	 */
	public static Date getDateBeforeAsDate(int days) {
		java.util.Calendar calendar = java.util.Calendar.getInstance();
		calendar.add(java.util.Calendar.DAY_OF_MONTH, -days);
		return calendar.getTime();
	}

	/**
	 * 获取指定天数前的日期时间字符串
	 * 
	 * @param days   天数（正数表示过去，负数表示未来）
	 * @param format 日期格式
	 * @return 指定天数前的日期时间字符串
	 */
	public static String getDateTimeBefore(int days, String format) {
		java.util.Calendar calendar = java.util.Calendar.getInstance();
		calendar.add(java.util.Calendar.DAY_OF_MONTH, -days);
		return parseDateToStr(format, calendar.getTime());
	}

	/**
	 * 获取30天前的日期时间字符串
	 * 
	 * @param format 日期格式
	 * @return 30天前的日期时间字符串
	 */
	public static String getDateTime30DaysBefore(String format) {
		return getDateTimeBefore(30, format);
	}

	/**
	 * 上个月第一天
	 * 
	 * @param date
	 * @return
	 */
	public static LocalDate getLastMonthFirstDate(LocalDate date) {
		int year = date.getYear();
		int month = date.getMonthValue(); // 示例月份（1-12，代表1月到12月）

		// 获取当月第一天和最后一天
		YearMonth yearMonth = YearMonth.of(year, month);
		LocalDate firstDay = yearMonth.atDay(1);

		// 获取当月第一天是星期几（1-7，1代表星期一，7代表星期日）
		DayOfWeek dayOfWeek = firstDay.getDayOfWeek();
		int firstDayOfWeek = dayOfWeek.getValue(); // 周一=1, 周二=2, ..., 周日=7

		// 不需要调整，因为Java的DayOfWeek已经周一开始，直接使用getValue()即可
		// 获取上个月最后一天
		YearMonth prevYearMonth = yearMonth.minusMonths(1);
		int prevMonthLastDayValue = prevYearMonth.lengthOfMonth();

		// 添加上个月最后几天
		int startFrom = prevMonthLastDayValue - firstDayOfWeek + 2; // 计算上个月开始显示的日期

		// 如果startFrom超过上个月的天数，则计入到下个月
		if (startFrom > prevMonthLastDayValue) {
			int nextMonthDay = startFrom - prevMonthLastDayValue;
			return yearMonth.atDay(nextMonthDay);
		} else {
			return prevYearMonth.atDay(startFrom);
		}
	}

	/**
	 * 上个月最后一天
	 * 
	 * @param date
	 * @return
	 */
	public static LocalDate getLastMonthLastDate(LocalDate date) {
		int year = date.getYear();
		int month = date.getMonthValue(); // 示例月份（1-12，代表1月到12月）

		// 获取当月第一天和最后一天
		YearMonth yearMonth = YearMonth.of(year, month);
		LocalDate firstDay = yearMonth.atDay(1);
		int daysInMonth = yearMonth.lengthOfMonth();
		// 获取当月第一天是星期几（1-7，1代表星期一，7代表星期日）
		DayOfWeek dayOfWeek = firstDay.getDayOfWeek();
		int firstDayOfWeek = dayOfWeek.getValue(); // 周一=1, 周二=2, ..., 周日=7

		// 添加下个月前几天（补全日历网格）
		final int totalCells = 42; // 6行×7列
		int nextMonthDays = totalCells - (daysInMonth + firstDayOfWeek - 1);
		YearMonth nextYearMonth = yearMonth.plusMonths(1);

		LocalDate atDay = nextYearMonth.atDay(nextMonthDays);
		return atDay;
	}

	/**
	 * 格式化时间差，返回中文描述
	 * 
	 * @param dateTime 要格式化的时间
	 * @return 时间差描述字符串
	 */
	public static String formatTimeAgo(LocalDateTime dateTime) {
		if (dateTime == null) {
			return "";
		}

		LocalDateTime now = LocalDateTime.now();
		Duration duration = Duration.between(dateTime, now);
		long seconds = duration.getSeconds();

		// 计算各种时间单位
		long minutes = seconds / 60;
		long hours = minutes / 60;
		long days = hours / 24;
		long months = days / 30;
		long years = days / 365;

		// 按照优先级返回相应的描述
		if (seconds < 30) {
			return "半分钟";
		} else if (seconds < 60) {
			return "一秒内";
		} else if (minutes < 1) {
			return "一分钟内";
		} else if (minutes == 1) {
			return "一分钟";
		} else if (minutes < 60) {
			return minutes + " 分钟";
		} else if (hours < 1) {
			return "大约一小时";
		} else if (hours == 1) {
			return "1 小时";
		} else if (hours < 24) {
			return "大约 " + hours + " 小时";
		} else if (days == 1) {
			return "一天";
		} else if (days < 30) {
			return days + " 天";
		} else if (months == 1) {
			return "大约一个月";
		} else if (months < 12) {
			return "大约 " + months + " 个月";
		} else if (years == 1) {
			return "一年";
		} else {
			return "超过 " + years + " 年";
		}
	}

	/**
	 * 生成完整的时间描述，类似 Redmine 的 authoring 方法
	 * 
	 * @param author      作者名称
	 * @param createdTime 创建时间
	 * @param isUpdate    是否为更新时间
	 * @return 完整的时间描述字符串
	 */
	public static String formatTimeByAuthor(String author, LocalDateTime createdTime, boolean isUpdate) {
		String timeDesc = formatTimeAgo(createdTime);

		if (isUpdate) {
			return "由 " + author + " 更新于 " + timeDesc + " 之前";
		} else {
			return "由 " + author + " 在 " + timeDesc + " 之前添加";
		}
	}

	/**
	 * 生成创建时间描述
	 * 
	 * @param author      作者名称
	 * @param createdTime 创建时间
	 * @return 创建时间描述字符串
	 */
	public static String formatCreatedTime(String author, LocalDateTime createdTime) {
		return formatTimeByAuthor(author, createdTime, false);
	}

	/**
	 * 生成更新时间描述
	 * 
	 * @param author      作者名称
	 * @param updatedTime 更新时间
	 * @return 更新时间描述字符串
	 */
	public static String formatUpdatedTime(String author, LocalDateTime updatedTime) {
		return formatTimeByAuthor(author, updatedTime, true);
	}

	/**
	 * 仅返回更新时间描述（不包含作者）
	 * 
	 * @param updatedTime 更新时间
	 * @return 更新时间描述字符串
	 */

	/**
	 * 计算两个LocalDateTime之间的时间差
	 * 
	 * @param startTime 开始时间
	 * @param endTime 结束时间
	 * @return 时间差字符串（如："2天3小时45分钟"）
	 */
	public static String calculateTimeDifference(LocalDateTime startTime, LocalDateTime endTime) {
		if (startTime == null || endTime == null) {
			return null;
		}
		
		Duration duration = Duration.between(startTime, endTime);
		long totalSeconds = Math.abs(duration.getSeconds());
		
		long days = totalSeconds / (24 * 60 * 60);
		long hours = (totalSeconds % (24 * 60 * 60)) / (60 * 60);
		long minutes = (totalSeconds % (60 * 60)) / 60;
		
		StringBuilder result = new StringBuilder();
		
		if (days > 0) {
			result.append(days).append("天");
		}
		if (hours > 0) {
			result.append(hours).append("小时");
		}
		if (minutes > 0) {
			result.append(minutes).append("分钟");
		}
		
		// 如果所有时间单位都为0，返回"0分钟"
		if (result.length() == 0) {
			return "0分钟";
		}
		
		return result.toString();
	}

	/**
	 * 计算两个LocalDateTime之间的小时差（精确到小数点后1位）
	 * 
	 * @param startTime 开始时间
	 * @param endTime 结束时间
	 * @return 小时差（保留1位小数）
	 */
	public static double calculateHoursDifference(LocalDateTime startTime, LocalDateTime endTime) {
		if (startTime == null || endTime == null) {
			return 0.0;
		}
		
		Duration duration = Duration.between(startTime, endTime);
		long totalMinutes = Math.abs(duration.toMinutes());
		
		// 将分钟转换为小时，保留1位小数
		return Math.round(totalMinutes / 6.0) / 10.0;
	}

	/**
	 * 时间格式化工具类，实现类似 Redmine 的时间显示逻辑 由 xu wang 在 大约 2 个月 之前添加. 更新于 一分钟内 之前.
	 */
	public static String formatUpdatedTimeOnly(LocalDateTime updatedTime) {
		String timeDesc = formatTimeAgo(updatedTime);
		return timeDesc;
	}

}
